#ifndef ZIYA_LINUX_MEMORY_MEMBLOCK_H
#define ZIYA_LINUX_MEMORY_MEMBLOCK_H

#include "types.h"
#define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t) 0)
#define MEMBLOCK_ALLOC_ACCESSIBLE 0
#define MEMBLOCK_ALLOC_KASAN 1

enum memblock_flags
{
    MEMBLOCK_NONE = 0x0,
    MEMBLOCK_HOTPLUG = 0x1,
    MEMBLOCK_MIRROR = 0x2,
    MEMBLOCK_NOMAP = 0x4,
};

struct memblock_region
{
    phys_addr_t base;
    phys_addr_t size;
    enum memblock_flags flags;
#ifdef CONFIG_HAVE_MEMBLOCK_NONE_MAP
    int nid;
#endif
};

struct memblock_type
{
    unsigned long cnt;
    unsigned long max;
    phys_addr_t total_size;
    struct memblock_region *regions;
    char* name;
};

struct memblock
{
    bool bottom_up;
    phys_addr_t current_limit;
    struct memblock_type memory;
    struct memblock_type reserved;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
    struct memblock_type physmem;
#endif
};

#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
int memblock_set_node(phys_addr_t base, phys_addr_t size, struct memblock_type* type, int nid);

static inline void memblock_set_region_node(struct memblock_region* r, int nid)
{
    r->nid = nid;
}

static inline int  memblock_get_region_node(const struct memblock_region* r)
{
    return r->nid;
}
#else
static inline void memblock_set_region_node(struct memblock_region *r, int nid)
{

}

static inline int memblock_get_region_node(const struct memblock_region* r)
{
    return 0;
}
#endif

phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
    phys_addr_t size, phys_addr_t align);

int memblock_add_range(struct memblock_type* type,
    phys_addr_t base, phys_addr_t size,
    int nid, enum memblock_flags flags);

int memblock_add(phys_addr_t base, phys_addr_t size);

void memblock_memory_print();

void memblock_reserved_print();

void memblock_test(void);
#endif